package ikcp

import "container/list"
import "math/rand"
import "time"

func iclock() int32 {
	return int32((time.Now().UnixNano() / 1000000) & 0xffffffff)
}

type DelayPacket struct {
	_ptr  []byte
	_size int
	_ts   int32
}

func (p *DelayPacket) Init(size int, src []byte) {
	p._ptr = make([]byte, size)
	p._size = size
	copy(p._ptr, src[:size])
}

func (p *DelayPacket) ptr() []byte    { return p._ptr }
func (p *DelayPacket) size() int      { return p._size }
func (p *DelayPacket) ts() int32      { return p._ts }
func (p *DelayPacket) setts(ts int32) { p._ts = ts }

type DelayTunnel struct{ *list.List }
type Random *rand.Rand
type LatencySimulator struct {
	current                        int32
	lostrate, rttmin, rttmax, nmax int
	p12                            DelayTunnel
	p21                            DelayTunnel
	r12                            *rand.Rand
	r21                            *rand.Rand
}

// lostrate: 往返一周丢包率的百分比，默认 10%
// rttmin：rtt最小值，默认 60
// rttmax：rtt最大值，默认 125
//func (p *LatencySimulator)Init(int lostrate = 10, int rttmin = 60, int rttmax = 125, int nmax = 1000):
func (p *LatencySimulator) Init(lostrate, rttmin, rttmax, nmax int) {
	p.r12 = rand.New(rand.NewSource(9))
	p.r21 = rand.New(rand.NewSource(99))
	p.p12 = DelayTunnel{list.New()}
	p.p21 = DelayTunnel{list.New()}
	p.current = iclock()
	p.lostrate = lostrate / 2 // 上面数据是往返丢包率，单程除以2
	p.rttmin = rttmin / 2
	p.rttmax = rttmax / 2
	p.nmax = nmax
}

// 发送数据
// peer - 端点0/1，从0发送，从1接收；从1发送从0接收
func (p *LatencySimulator) send(peer int, data []byte, size int) int {
	rnd := 0
	if peer == 0 {
		rnd = p.r12.Intn(100)
	} else {
		rnd = p.r21.Intn(100)
	}
	//println("!!!!!!!!!!!!!!!!!!!!", rnd, p.lostrate, peer)
	if rnd < p.lostrate {
		return 0
	}
	pkt := &DelayPacket{}
	pkt.Init(size, data)
	p.current = iclock()
	delay := p.rttmin
	if p.rttmax > p.rttmin {
		delay += rand.Int() % (p.rttmax - p.rttmin)
	}
	pkt.setts(p.current + int32(delay))
	if peer == 0 {
		p.p12.PushBack(pkt)
	} else {
		p.p21.PushBack(pkt)
	}
	return 1
}

// 接收数据
func (p *LatencySimulator) recv(peer int, data []byte, maxsize int) int32 {
	var it *list.Element
	if peer == 0 {
		it = p.p21.Front()
		if p.p21.Len() == 0 {
			return -1
		}
	} else {
		it = p.p12.Front()
		if p.p12.Len() == 0 {
			return -1
		}
	}
	pkt := it.Value.(*DelayPacket)
	p.current = iclock()
	if p.current < pkt.ts() {
		return -2
	}
	if maxsize < pkt.size() {
		return -3
	}
	if peer == 0 {
		p.p21.Remove(it)
	} else {
		p.p12.Remove(it)
	}
	maxsize = pkt.size()
	copy(data, pkt.ptr()[:maxsize])
	return int32(maxsize)
}
